﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using System.Web;
using System.DirectoryServices.AccountManagement;
using System.Reflection;

namespace Chisholm.Windows.Live.Security
{
    /// <summary>
    /// This implements the security provider and returns a users Windows Live account based on their
    /// given Active Directory login
    /// </summary>
    public class ActiveDirectoryEmailSecurity : ISecurityProvider
    {
        /// <summary>
        /// This searches the given security provider, and returns the Windows Live ID for the 
        /// given identity credentials passed through
        /// </summary>
        /// <param name="credentials">An object containing the particular identity credentials</param>
        /// <param name="configuration">A configuration string (if required) for the provider</param>
        /// <param name="windowslivedomain">The Windows Live e-mail domain (e.g. my.uni.edu.au)</param>
        /// <returns>The Windows Live ID for the given credentials</returns>
        public string GetWindowsLiveID(object credentials, string configuration, string windowslivedomain)
        {
            // First check to ensure that the given credentials are a string, and extract the 
            // username from the string
            if (credentials != null && credentials is string)
            {
                // Grab the username component of the given credentials string
                string[] creds = ((string)credentials).Split('\\');
                string username = String.Empty;
                if (creds.Length == 2)
                    username = creds[1];
                else
                    username = creds[0];

                // Now check to ensure the configuration is valid
                string[] configstrings = configuration.Split(';');
                if (configstrings.Length >= 2)
                {
                    // This configuration is valid and contains a DOMAIN, USER, PASSWORD and PROPERTY
                    string domain = String.Empty;
                    string domainuser = String.Empty;
                    string domainpassword = String.Empty;
                    List<string> emailproperties = new List<string>();

                    foreach (string thisconfig in configstrings)
                        if (thisconfig.Split('=').Length == 2)
                        {
                            // This is a valid setting, so update the appropriate value
                            string[] configvalues = thisconfig.Split('=');
                            if (configvalues[0].ToUpper() == "DOMAIN")
                                domain = configvalues[1];
                            else if (configvalues[0].ToUpper() == "USER")
                                domainuser = configvalues[1];
                            else if (configvalues[0].ToUpper() == "PASSWORD")
                                domainpassword = configvalues[1];
                            else if (configvalues[0].ToUpper() == "PROPERTY")
                            {
                                // See if multiple properties have been specified
                                string[] multiprops = configvalues[1].Split(',');
                                foreach (string thisprop in multiprops)
                                    emailproperties.Add(thisprop);
                            }
                        }

                    // Connect to the domain
                    PrincipalContext domainaccess = null;

                    try
                    {
                        if (domainuser != String.Empty && domainpassword != String.Empty)
                        {
                            // The domain has explicit credentials so use them
                            domainaccess = new PrincipalContext(ContextType.Domain,
                                domain, domainuser, domainpassword);
                        }
                        else
                        {
                            // The domain is using the credentials of the running service
                            domainaccess = new PrincipalContext(ContextType.Domain, domain);
                        }
                    }
                    catch
                    {
                        return String.Empty;
                    }

                    if (domainaccess != null)
                    {
                        // We have valid domain access settings, so attempt to validate their credentials
                        try
                        {
                            // Then grab the given users record                            
                            ExtendedUserPrincipal user = ExtendedUserPrincipal.FindByIdentity(domainaccess, username);                            
                            
                            if (user != null)
                            {
                                // Check whether there is a property value available in the list with
                                // the specified windows live domain
                                foreach (string thisproperty in emailproperties)
                                {
                                    string thisvalue = user.GetExtendedValue<string>(thisproperty);
                                    if (thisvalue != null && thisvalue.ToUpper().Contains(windowslivedomain.ToUpper()))
                                        return thisvalue;
                                }

                                // No property was found, so return an empty string
                                return String.Empty;
                            }
                            else
                            {
                                // Return an empty string as the user doesn't exist
                                return String.Empty;
                            }
                        }
                        catch 
                        {
                            // Return an empty string as the authentication failed
                            return String.Empty;
                        }
                    }
                    else
                        // Return an empty string as the configuration isn't valid
                        return String.Empty;
                }
                else
                    // Return an empty string as the configuration isn't valid
                    return String.Empty;
            }
            else
                // Return an empty string as the credentials are not valid
                return String.Empty;
        }
    }
}
